package org.javaforever.oville;

import java.util.ArrayList;
import java.util.List;

public class Word {
	private String varName;
	private byte [] word = new byte[8];
	public String getVarName() {
		return varName;
	}
	public void setVarName(String varName) {
		this.varName = varName;
	}
	public byte[] getWord() {
		return word;
	}
	public void setWord(byte[] word) {
		this.word = word;
	}
	
	public byte getByte(int pos) {
		return this.getWord()[pos%8];
	}
	
	public String toBinStr() throws ValidateException{
		StringBuilder sb = new StringBuilder();
		for (int i=0;i<8;i++) {
			byte bb = word[i];
			if (bb<0) bb += 256;
			for (int j=7;j>=0;j--) {
				byte bit = (byte)((bb >>> j)%2);
				if (bit<0) bit += 2;
				//System.out.println(bit);
				sb.append(bit);
			}
		}
		return sb.toString();
	}
	
	public String toQuadStr() throws ValidateException{
		String bin = this.toBinStr();
		StringBuilder sb = new StringBuilder();
		for (int i=0;i<32;i++) {
			sb.append(StringUtil.binDigToQuad(bin.substring(i*2,(i+1)*2)));
		}
		return sb.toString();
	}	
	
	public String toHexStr() throws ValidateException{
		String bin = this.toBinStr();
		StringBuilder sb = new StringBuilder();
		for (int i=0;i<16;i++) {
			sb.append(StringUtil.binDigToHex(bin.substring(i*4,(i+1)*4)));
		}
		return sb.toString();
	}	
	
	public TextWord toTextWord(String pattern) throws ValidateException{
		if (pattern.length() != 4) throw new ValidateException("Wrong word pattern quad string length!");
		String qdStr = this.toQuadStr();
		qdStr = qdStr.replace('0', pattern.charAt(0));
		qdStr = qdStr.replace('1', pattern.charAt(1));
		qdStr = qdStr.replace('Q', pattern.charAt(2));
		qdStr = qdStr.replace('P', pattern.charAt(3));
		TextWord tw = TextWord.fromStr(qdStr);
		return tw;
	}	
	
	public static Word fromQuadStr(String quadStr) throws ValidateException{
		if (quadStr.length() != 32) throw new ValidateException("Wrong word quad string length!");
		for (int i=0;i<quadStr.length();i++) {
			if (quadStr.charAt(i)!='0'&&quadStr.charAt(i)!='1'&&quadStr.charAt(i)!='P'&&quadStr.charAt(i)!='Q'){
				throw new ValidateException("Wrong char in quad string!");
			}
		}
		List<Quad> quads = new ArrayList<>();
		for (int i=31;i>=0;i--) {
			quads.add(new Quad(quadStr.charAt(i)));
		}
		Word w = new Word();
		byte [] bb = new byte[8];
		for (int i=0;i<quads.size()/4;i++) {
			byte currentBb = fourQuadToByte(quads.subList(i*4, i*4+4));
			bb [7-i] = currentBb;
		}
		w.setWord(bb);
		return w;
	}
	
	public static byte fourQuadToByte(List<Quad> quads) throws ValidateException{
		if (quads.size() != 4) throw new ValidateException("Wrong size "+quads.size()+" for quad list!");
		byte result = 0;
		for (int i=0;i<quads.size();i++) {
			if ("1".equals(quads.get(i).toQuadStr())){
				result = (byte) (result |((byte) 0b01 <<(i*2)));
			} else if ("Q".equals(quads.get(i).toQuadStr())){
				result = (byte) (result |((byte) 0b10 <<(i*2)));
			} else if ("P".equals(quads.get(i).toQuadStr())){
				result = (byte) (result |((byte) 0b11 <<(i*2)));
			}
		}
		return result;
	}
	
	public boolean equals(Word w) throws ValidateException{
		return this.toQuadStr().equals(w.toQuadStr());
	}
	
	public static void main(String[] argv) throws ValidateException{
		Word w = new Word();
		w.setVarName("word");
		byte [] bb = new byte[8];
		bb[0] = (byte)0b01010101;
		bb[1] = (byte)0b10101010;
		bb[2] = (byte)0b10111010;
		w.setWord(bb);
		System.out.println(w.toBinStr());
		System.out.println(w.toHexStr());
		System.out.println(w.toQuadStr());
		
		List<Quad> quads = new ArrayList<>();
		quads.add(new Quad("1"));
		quads.add(new Quad("0"));
		quads.add(new Quad("Q"));
		quads.add(new Quad("P"));
		
		byte bbb = fourQuadToByte(quads);
		byte [] bb2 = new byte[8];
		bb2[0] = bbb;
		
		Word w2 = new Word();
		w2.setWord(bb2);
		System.out.println("Jerry:"+w2.toBinStr());
		System.out.println("jerry2:"+w2.toQuadStr());
		
		Word w3 = fromQuadStr("10QP10QP10QP10QP10QP10QP10QP10QP");
		System.out.println("jerry3:"+w3.toQuadStr());
	}

}
